import inquirer from 'inquirer';
import fs from 'fs';
import path from 'path';

// 路径
const templatePath: string = './scripts/templates';
const rootDirectory: string = './src';

// 交互模式
let questionObjects: any = [
  {
    type: 'input',
    name: 'componentName',
    message: '请输入文件名称：',
    validate(value: string): true | Error {
      return !value.length ? new Error('文件名称不能为空') : true;
    },
  },
  {
    type: 'list', // 类型为列表选择
    name: 'choicePageType', // 问题的名称，用于获取用户答案
    message: '请选择你要生成的模板：', // 提示信息
    choices: [
      {
        name: 'vue文件',
        value: 'VUE',
      },
      {
        name: 'vue组件',
        value: 'VUE_COMPONENT',
      },
      {
        name: 'uni-app文件',
        value: 'UNI',
      },
    ], // 可选项
  },
  {
    type: 'list',
    name: 'choiceTemplate',
    message: '请选择你要生成的模板：',
    choices: [],
  },
  {
    type: 'list',
    name: 'choiceCatalogue',
    message: '请选择目标目录：',
    choices: [],
  },
  {
    type: 'confirm',
    name: 'isCreateDirectory',
    message: '是否创建同名目录？',
    default: true,
  },
];

/**
 * 用户交互
 * @param index
 */
async function inquirerPrompt(index: number): Promise<string> {
  const answers = await inquirer.prompt(questionObjects[index]);
  return answers[questionObjects[index].name];
}

/**
 * 读取目录下的文件列表
 * @param dirPath 目录路径
 * @param isType 文件类型
 */
async function readPathFileList(dirPath: string, isType: string = 'isDirectory') {
  try {
    const files = await fs.promises.readdir(dirPath);
    let backFiles = [];
    for (const fileName of files) {
      const filePath = path.join(dirPath, fileName);
      const stats: any = await fs.promises.stat(filePath);
      if (stats[isType]()) {
        backFiles.push({
          name: fileName,
          path: filePath,
        });
      }
    }
    return backFiles;
  } catch (err) {
    console.error('无法读取目录:', err);
  }
}

/**
 * 格式化模板的函数
 * @param path 模板路径
 * @param fileName 文件名称
 */
async function formatTemplate(path: string, fileName: string) {
  let fileContent = await fs.promises.readFile(path, 'utf8');
  fileContent = fileContent.replace(/fileName/g, fileName);
  return fileContent;
}

/**
 * 选择模板的函数
 * @param fileName 文件名称
 * @returns 模板内容
 */
async function choiceTemplateFun(fileName: string): Promise<string> {
  let temFiles: { name: string; path: string }[] | undefined = await readPathFileList(templatePath, 'isFile');
  questionObjects[2].choices = temFiles!.map(
    (item: { name: string; path: string }): { name: string; value: string } => {
      return {
        name: item.name,
        value: item.path,
      };
    },
  );
  const choiceTemplatePath: string = await inquirerPrompt(2);
  const temContent: string = await formatTemplate(choiceTemplatePath, fileName);
  return temContent;
}

/**
 * 选择目标目录的函数
 * @returns 目标目录路径
 */
async function selectTargetDirectoryFun(): Promise<string> {
  const targetCatalogue: any = await readPathFileList(rootDirectory, 'isDirectory');
  questionObjects[3].choices = targetCatalogue.map(
    (item: { name: string; path: string }): { name: string; value: string } => {
      return {
        name: item.name,
        value: item.path,
      };
    },
  );
  const choiceCatalogue: string = await inquirerPrompt(3);
  return choiceCatalogue;
}

/**
 * 创建初始化文件的函数
 * @param fileName 文件名
 * @param temContent 文件内容
 * @param superiorDirectory 上级目录路径
 * @param isCreateDirectory 是否创建同名目录
 */
async function createInitializationFileFun(
  fileName: string,
  temContent: string,
  superiorDirectory: string,
  isCreateDirectory: boolean,
): Promise<void> {
  try {
    // 构建基础文件路径
    let filePath = path.join(superiorDirectory, fileName);
    // 如果需要创建目录，则先创建目录再写文件
    if (isCreateDirectory) {
      await fs.promises.mkdir(filePath); // 创建目录
      filePath = path.join(filePath, `${fileName}.vue`); // 在新建目录下创建文件
    } else {
      filePath += '.vue'; // 否则直接在上级目录下创建文件
    }
    // 写入文件内容
    await fs.promises.writeFile(filePath, temContent);
    console.log('文件创建成功');
  } catch (error) {
    console.error('创建文件时发生错误:', error);
  }
}

/**
 * 主函数
 */
(async (): Promise<void> => {
  try {
    // 输入文件名称
    const fileName = await inquirerPrompt(0);
    // 选择模板
    const temContent = await choiceTemplateFun(fileName);
    // 选择目标目录
    const superiorDirectory = await selectTargetDirectoryFun();
    // 询问是否创建同名目录
    const isCreateDirectory: string = await inquirerPrompt(4);
    // 创建初始化文件
    await createInitializationFileFun(fileName, temContent, superiorDirectory, Boolean(isCreateDirectory));
  } catch (error) {
    console.error('发生错误:', error);
  }
})();

/**
 * TIP：自动化创建vue文件
 * 1. 输入文件名称
 * 2. 选择模板
 * 3. 选择目标目录
 * 4. 询问是否创建同名目录
 * 5. 创建初始化文件
 *
 * 使用模板
 * 1. inquirer - 命令行用户交互对话库
 * 2. fs - 文件系统操作
 * 3. path - 路径处理
 */
